
import { ClientOption, Events, SocketConnectStatus } from "pitayaclient";
import { AsyncDelegate, director, error, Game, game, log, Scene, warnID } from "cc";

import { AllEventResponsePairs, SocialGameClientOption } from "sgc";
import { WECHAT } from "cc/env";


import { GlobalEventConstant } from "../../constant/GlobalEventConstant";
import { Manager } from "../../manager";
import { BaseManager } from "../../manager/BaseManager";
import { ExtendedClientOption, WrapperSocialGameClient } from "./wrapper-socialgame-client";
import { ReconnectPrompt } from "../../ui/reconnection/ReconnectPrompt";
import { SceneLayer } from "../../gui";


type ConnectionState = keyof Events | 'init' | 'online' | 'offline' | 'show' | 'hide' | 'reconnect' | 'destroy';

type ConnectionEvent = {
    [K in ConnectionState]: K extends 'error' | 'disconnect' | 'close' ? { type: K, ev?: Event | string } : { type: K, ret?: any }
}[ConnectionState];


// ---------------------- 新增管理类 ----------------------
export class SocialGameClientManager extends BaseManager {

    private managedClients: Map<string, WrapperSocialGameClient> = new Map();

    /**在线 */
    private isGlobalOnline = true;

    /**在后台 */
    private isInBackground = false;

    /**正在重连 */
    private reconnecting = false;

    /**后台委托 */
    readonly onEventHideDelegate: AsyncDelegate<(option?: WechatMinigame.GeneralCallbackResult | undefined) => (Promise<void> | void)> = new AsyncDelegate()
    /**前台委托 */
    readonly onEventShowDelegate: AsyncDelegate<(option?: WechatMinigame.OnShowListenerResult | undefined) => (Promise<void> | void)> = new AsyncDelegate()
    /**重载场景委托 */
    readonly onEventReloadSceneDelegate: AsyncDelegate<() => (Promise<void> | void)> = new AsyncDelegate()

    /**重连定时器 */
    private reconnectTimer: ReturnType<typeof setTimeout> | null = null;


    /** 上次触发重连时间 */
    private lastReconnectTime = 0;
    /** 重连冷却间隔（毫秒） */
    private RECONNECT_COOLDOWN = 1500;

    private pendingShowOptions: WechatMinigame.OnShowListenerResult[] = [];

    private scheduleReconnect(delay: number = 2000) {
        if (this.reconnectTimer) {
            clearTimeout(this.reconnectTimer);
            this.reconnectTimer = null;
        }

        this.reconnectTimer = setTimeout(() => {
            this.reconnectTimer = null;
            this.triggerReconnectAll();
        }, delay);
    }

    get activeClients() {
        return Array.from(this.managedClients)
            .map(([_, client]) => client)
            .filter(client => client.socket);
    }

    constructor(cat: Manager) {
        super(cat);
        this.initGlobalListeners();
    }

    /**
   * 创建并注册WebSocket客户端
   * @param name 客户端唯一标识（如"game", "room"）
   * @param clientOption 客户端配置选项
   * @param opts 社交游戏选项
   * @param eventResponsePairs 事件响应配置
   */
    createWebSocket(
        name: string,
        clientOption: ExtendedClientOption,
        opts: Partial<SocialGameClientOption>,
        eventResponsePairs: Partial<AllEventResponsePairs>,
    ): WrapperSocialGameClient {
        // 清理同名旧客户端
        if (this.managedClients.has(name)) {
            const oldClient = this.managedClients.get(name)!;
            // 主动断开并销毁
            oldClient.destroy();
            log(`清理旧的 ${name} 客户端`);
        }

        // 创建客户端实例
        const client = new WrapperSocialGameClient(
            name, // 将名称注入配置
            opts,
            eventResponsePairs,
            Object.assign({ reconnectMaxAttempts: Infinity }, {
                ...clientOption,
                // 强制关闭自动重连，由管理器统一控制
                isAutoConnect: false,
                isArrayBuffer: WECHAT
            })
        )
        // 注册并返回
        this.register(client);

        return client;
    }


    // 注册客户端
    register(client: WrapperSocialGameClient) {
        client.on('reconnected', this.handleSingleReconnect);
        client.on('close', this.handleSingleClose);
        client.on('kick', this.handleSingleKick);

        this.managedClients.set(client.name, client);
    }

    // 注销客户端
    unregister(client: WrapperSocialGameClient) {
        client.off('reconnected', this.handleSingleReconnect);
        client.off('close', this.handleSingleClose);
        client.off('kick', this.handleSingleKick);
        this.managedClients.delete(client.name);
    }

    private initGlobalListeners() {
        // 网络状态监听
        this.cat.event
            .on(GlobalEventConstant.ONLINE, () => this.handleGlobalStateChange('online'), this)
            .on(GlobalEventConstant.OFFLINE, () => this.handleGlobalStateChange('offline'), this)
        if (WECHAT) {
            wx.onShow((option) => {
                this.handleGlobalStateChange('show', option)
            })
            wx.onHide((option) => {
                this.handleGlobalStateChange('hide', option)
            })
        } else {
            game.on(Game.EVENT_SHOW, () => this.handleGlobalStateChange('show'))
            game.on(Game.EVENT_HIDE, () => this.handleGlobalStateChange('hide'))
        }

    }

    private async handleGlobalStateChange(state: ConnectionState, option?: WechatMinigame.OnShowListenerResult | WechatMinigame.GeneralCallbackResult) {
        // 更新全局状态
        switch (state) {
            case 'online':
                this.cat.gui.hideLoading().showToast({ title: ReconnectPrompt.ONLINE })
                this.isGlobalOnline = true;
                this.safeTriggerReconnectAll();
                break;
            case 'offline':
                this.isGlobalOnline = false;
                this.disconnectAll(true);
                this.cat.gui.showLoading({ title: ReconnectPrompt.OFFLINE });
                break;
            case 'show':
                this.isInBackground = false;
                log('监听前台 show', option)
                // 入队，保存本次 show 参数
                if (option) this.pendingShowOptions.push(option as WechatMinigame.OnShowListenerResult);
                await this.safeTriggerReconnectAll();
                break;
            case 'hide':
                log('监听前台 hide')
                await this.onEventHideDelegate.dispatch(option as WechatMinigame.GeneralCallbackResult);
                this.isInBackground = true;
                this.disconnectAll(true);
                break;
        }
    }

    private async safeTriggerReconnectAll() {
        const now = Date.now();

        // 如果没有客户端需要重连，直接执行 reload + show 队列
        if (this.reconnecting || (!this.isGlobalOnline || this.isInBackground) || this.managedClients.size === 0) {
            console.log('[safeTriggerReconnectAll] 没有需要重连的客户端，直接 dispatch');
            await this.dispatchReloadAndShow();
            return;
        }

        // 防抖 + 锁处理（只有有客户端才防抖）
        if (this.reconnecting) {
            console.log('[safeTriggerReconnectAll] 正在重连中，跳过本次');
            return;
        }
        if (now - this.lastReconnectTime < this.RECONNECT_COOLDOWN) {
            console.log('[safeTriggerReconnectAll] 距上次重连过近，跳过本次');
            return;
        }

        this.lastReconnectTime = now;
        await this.triggerReconnectAll();
    }

    private async dispatchReloadAndShow() {
        await this.onEventReloadSceneDelegate.dispatch();

        // 触发所有 pending show 回调
        while (this.pendingShowOptions.length > 0) {
            const showOption = this.pendingShowOptions.shift();
            this.onEventShowDelegate.dispatch(showOption!);
        }
    }

    // 统一触发所有WS重连
    private async triggerReconnectAll() {
        console.log('触发所有客户端重连[正在重连][在线][后台][ws数量]', this.reconnecting, this.isGlobalOnline, this.isInBackground, this.managedClients.size);

        // 如果没有任何客户端需要重连，直接返回
        if (this.reconnecting || (!this.isGlobalOnline || this.isInBackground) || this.managedClients.size === 0) {
            await this.dispatchReloadAndShow();
            return
        }

        this.reconnecting = true;
        this.cat.gui.showLoading({ title: '正在重连' });

        try {
            await Promise.allSettled(
                this.activeClients.map(async (client) => {
                    try {
                        // 1. 等待物理层重连
                        await client.reconnectPromise();
                    } catch (err) {
                        error(`${client.name}服重连失败`, err);
                        // cat.gui.showToast({ title: `${client.name}服重连失败` });
                        // 不抛出错误，让 Promise.allSettled 收集结果
                    }
                })
            );

            // 检查是否有客户端未成功连接
            const failedClients = this.activeClients.filter(client =>
                client.socketConnectStatus !== SocketConnectStatus.CONNECTED
            );

            if (failedClients.length > 0) {
                failedClients.map((name) => {
                    console.error("部分WS重连失败：", name);
                })
                // 可以在一段时间后再次尝试重连
                log('2s后重连所有客户端');
                this.reconnecting = false
                this.scheduleReconnect();
            } else {
                this.reconnecting = false;
            }
        } catch (e) {
            this.reconnecting = false;
            throw e;
        }


    }

    // 统一断开所有WS
    private disconnectAll(active: boolean) {
        if (this.activeClients.every(c => c.socket?.readyState !== WebSocket.OPEN)) return;
        this.managedClients.forEach(client => {
            log('断开连接', client.name, active, client.socket);
            client.disconnect(active);
        });
    }

    private handleSingleClose = () => {
        if (!this.reconnecting) {
            log('3s后重连所有客户端');
            this.scheduleReconnect(3000);
        }
    }

    // 单个WS重连成功回调
    private handleSingleReconnect = async () => {
        if (this.activeClients.every(client => client.socketConnectStatus === SocketConnectStatus.CONNECTED)) {
            log('单个WS重连成功回调===', this.managedClients)
            await Promise.allSettled(
                this.activeClients.map(async (client) => {
                    // 连接社交游戏服务
                    try {
                        // 2. 执行业务层连接请求
                        await client.connectRequest();
                    } catch (err) {
                        error(`${client.name}服登录错误`, err);
                        this.cat.gui.showToast({ title: `登录${client.name}服错误` });
                    }
                })
            )
            if (this.reconnectTimer) {
                clearTimeout(this.reconnectTimer);
                this.reconnectTimer = null;
            }
            // 这里可能需要和cat.gui.reloadScene位置调换，需要等界面完成重载 再调用 (待测试优化,先记录)
            await this.onEventReloadSceneDelegate.dispatch()
            this.cat.gui.hideLoading()

            if (director.getScene()?.getComponentInChildren(SceneLayer)?.isReload) this.cat.gui.reloadScene(() => {
                // scene reload 完成后，逐个触发 show 回调
                while (this.pendingShowOptions.length > 0) {
                    const showOption = this.pendingShowOptions.shift();
                    this.onEventShowDelegate.dispatch(showOption!);
                }
            });
        }
    }

    // 被踢出
    private handleSingleKick = () => {
        this.cat.gui.showReconnect(ReconnectPrompt.KICK);
    }
}